package com.choosefine.paycenter.webgateway.pay.web.controller;

import com.abc.pay.client.Constants;
import com.abc.pay.client.TrxException;
import com.abc.pay.client.ebus.PaymentResult;
import com.choosefine.paycenter.channel.abc.api.impl.ABCQueryOderServiceImpl;
import com.choosefine.paycenter.channel.abc.entity.ABCOrderStatus;
import com.choosefine.paycenter.common.utils.UriUtils;
import com.choosefine.paycenter.common.utils.WebUtils;
import com.choosefine.paycenter.pay.api.PayBackService;
import com.choosefine.paycenter.pay.api.handler.PayBackHandler;
import com.choosefine.paycenter.pay.api.dispatcher.PayDispatcher;
import com.choosefine.paycenter.pay.dto.PayBackDto;
import com.choosefine.paycenter.pay.enums.NotifyType;
import com.choosefine.paycenter.pay.model.Payment;
import com.choosefine.paycenter.pay.service.PaymentService;
import com.google.common.base.Splitter;
import io.swagger.annotations.Api;
import io.undertow.servlet.spec.HttpServletRequestImpl;
import lombok.extern.slf4j.Slf4j;
//import org.apache.catalina.connector.Request;
//import org.apache.catalina.connector.RequestFacade;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import org.springframework.stereotype.Controller;
import org.springframework.util.ReflectionUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.ResponseBody;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Field;
import java.math.BigDecimal;
import java.util.Map;

/**
 * Comments：支付回调接收处理
 * Author：Jay Chang
 * Create Date：2017/4/14
 * Modified By：
 * Modified Date：
 * Why & What is modified：
 * Version：v1.0
 */
@Api(value = "支付回调处理",description = "张洁")
@Slf4j
@Controller
@RequestMapping("payBack")
public class PayCallbackController {
    @Autowired
    private PayDispatcher payDispatcher;//支付处理分发器
    @Autowired
    private PayBackService payBackProcessService;
    @Autowired
    private ABCQueryOderServiceImpl abcQueryOderService;

    @Autowired
    private PaymentService paymentService;

    /**
     * 同步回调
     * @param channel
     * @param request
     * @return
     */
    @RequestMapping("{channel}/{payType}/return")
    public String returnCallback(@PathVariable("channel") String channel, @PathVariable("payType") String payType, HttpServletRequest request) {
        log.info("bank return channel=" + channel + ",payType=" + payType + " callback: method=" + request.getMethod() + ",queryString=" + request.getQueryString() + "");
        Map<String, String> parameterMap = WebUtils.getInstance().getParameter2Map(request
                .getParameterMap());
        //建行B2B支付页面回调特殊处理
        if ("ccb".equalsIgnoreCase(channel) && "b2b_nb".equalsIgnoreCase(payType)) {
            String result = processCCBB2BCallbackParameters(request, parameterMap, "return");
            if (StringUtils.isNotBlank(result)) {
                return "redirect:" + result;
            }
        }
        PayBackDto payBackDto = new PayBackDto(parameterMap, channel, payType, NotifyType.RETURN);
        PayBackHandler payBackHandler = payDispatcher.getPayBackHandler(channel);
        String returnUrl = payBackHandler.doProcessReturn(payBackDto);
        return "redirect:"+returnUrl;
    }

    /**
     * 异步回调
     * @param channel
     * @return
     */
    @RequestMapping("{channel}/{payType}/notify")
    @ResponseBody
    public String notifyCallback(@PathVariable("channel") String channel, @PathVariable("payType") String payType, HttpServletRequest request) {
        log.info("bank notify channel=" + channel + ",payType=" + payType + " callback: method=" + request.getMethod() + ",queryString=" + request.getQueryString() + "");
        Map<String, String> parameterMap = WebUtils.getInstance().getParameter2Map(request.getParameterMap());
        //建行B2B支付页面回调特殊处理
        if ("ccb".equalsIgnoreCase(channel) && "b2b_nb".equalsIgnoreCase(payType)) {
            String result = processCCBB2BCallbackParameters(request, parameterMap, "notify");
            if (StringUtils.isNotBlank(result)) {
                return result;
            }
        }
        PayBackDto payBackDto = new PayBackDto(parameterMap, channel, payType, NotifyType.NOTIFY);
        PayBackHandler payBackHandler = payDispatcher.getPayBackHandler(channel);
        String result = payBackHandler.doProcessNotify(payBackDto);
        //返回结果给银行服务器
        return result;
    }

    /**
     * 农业银行支付结果服务器通知回调
     * 获取支付结果之后跳转通知页面
     * @param request
     * @return
     * @throws TrxException
     */
    @RequestMapping(value = "/abc/notify", produces = MediaType.TEXT_HTML_VALUE)
    @ResponseBody
    public String abcNotifyCallback(HttpServletRequest request) throws TrxException {
        System.out.print(request.getQueryString());
        String msg = request.getParameter("MSG");
        PaymentResult tResult = new PaymentResult(msg);
        String tMerchantPage = null;
        String OrderNo = tResult.getValue("OrderNo");//获得订单号
        String Amount = tResult.getValue("Amount");//获得订单金额
        BigDecimal PAYMENT = BigDecimal.valueOf(Double.valueOf(Amount));//转成我们自己数据库的类型
        //2、判断支付结果处理状态，进行后续操作
        if (tResult.isSuccess()) {
            //3、支付成功并且验签、解析成功
            payBackProcessService.doProcess(OrderNo);
            tMerchantPage = "http://10.233.4.11:8080/ebusclient/ResultSuccess.jsp";//通知成功页面
        } else {
            //先取得错误的信息
            String returnCode = tResult.getReturnCode();
            String errorMessage = tResult.getErrorMessage();
            log.info("returnCode:" + returnCode + "errorMessage:" + errorMessage);
            //TODO:可以根据错误码和错误信息来判断是什么错误从而可以执行下一步的操作
            //如果tResult表示未成功，先去平台查询该笔订单的支付是否已经支付成功只是因为签名的问题导致返回的结果失败
            Map map = abcQueryOderService.queryOder(Constants.PAY_TYPE_DIRECTPAY, "0", OrderNo);
            String status = (String) map.get("Status");
            if (ABCOrderStatus.ABC_ORDER_SUCCESS.equals(status)) {
                payBackProcessService.doProcess(OrderNo);
                tMerchantPage = "http://10.233.4.11:8080/ebusclient/ResultSuccess.jsp";
            } else {
                payBackProcessService.doFailureProcess(OrderNo);
                //4、支付成功但是由于验签或者解析报文等操作失败
                tMerchantPage = "http://10.233.4.11:8080/ebusclient/ResultFail.jsp";//通知失败页面
            }
        }
        return tMerchantPage;
    }


    private String processCCBB2BCallbackParameters(final HttpServletRequest request, final Map<String, String> parameterMap, String notifyType) {
        //undertow的解决方案
        String queryString = null;
        String originalQueryString = null;
        try {
            HttpServletRequestImpl requestImpl = (HttpServletRequestImpl) request;
            originalQueryString = requestImpl.getOriginalQueryString();
            queryString = new String(originalQueryString.getBytes("ISO-8859-1"), "GBK");
            final Map<String, String> queryParams = Splitter.on("&").withKeyValueSeparator("=").split(queryString);
            parameterMap.put("ACC_NAME", queryParams.get("ACC_NAME"));
            parameterMap.put("BRANCH_NAME", queryParams.get("BRANCH_NAME"));
            return null;
        } catch (Exception e) {
            log.error("建行B2B支付页面回调参数编解码处理失败:{},参数信息:{}", e, originalQueryString);
            final String paySn = parameterMap.get("ORDER_NUMBER");
            Payment payment = paymentService.findByPaySn(paySn);
            if ("return".equalsIgnoreCase(notifyType)) {
                return payment.getReturnUrl() + "?success=false&&amount=" + payment.getAmount() + "&message=" + UriUtils.getInstance().encode("建行B2B支付页面回调参数编解码处理失败", "UTF-8");
            } else {
                return "failure";
            }
        }

        //tomcat作为内置servlet容器时的解决方案(springboot1.4.2带的tomcat版本[8.5.6调试是OK])若是springboot 1.5.2及1.4.6带的tomcat
        // 会报Invalid character found in the request target. The valid characters are defined in RFC 7230 and RFC 3986
//        String queryString = null;
//        try {
//            RequestFacade requestFacade = (RequestFacade) request;
//            Field requestFieldOfRequestFacade = RequestFacade.class.getDeclaredField("request");
//            requestFieldOfRequestFacade.setAccessible(true);
//            Request cyoteRequest = (Request) ReflectionUtils.getField(requestFieldOfRequestFacade,request);
//            queryString = new String(cyoteRequest.getQueryString().getBytes("ISO-8859-1"),"GBK");
//            final Map<String, String> queryParams = Splitter.on("&").withKeyValueSeparator("=").split(queryString);
//            parameterMap.put("ACC_NAME",queryParams.get("ACC_NAME"));
//            parameterMap.put("BRANCH_NAME",queryParams.get("BRANCH_NAME"));
//            return null;
//        } catch (Exception e) {
//            log.error("建行B2B支付页面回调参数编解码处理失败:{},参数信息:{}",e,queryString);
//            final String paySn = parameterMap.get("ORDER_NUMBER");
//            Payment payment = paymentService.findByPaySn(paySn);
//            if("return".equalsIgnoreCase(notifyType)) {
//                return payment.getReturnUrl() + "?success=false&&amount=" + payment.getAmount() + "&message=" + UriUtils.getInstance().encode("建行B2B支付页面回调参数编解码处理失败", "UTF-8");
//            }else{
//                return "failure";
//            }
//        }

    }
}
